var RedisSMQ = require('rsmq');
var _ = require('../../shared/util');
module.exports = function(config) {
  return new MessageQueue(config);
};


var eventEmitter = require('events');

/**
 * MessageQueue
 */
class MessageQueue extends eventEmitter {
  /**
   * constructor
   * @param {Object} config
   * @param {String} config.host
   * @param {Number} config.port
   * @param {String} config.ns
   * @param {Object} config.options optional (Default: {}) The Redis
   */
  constructor(config) {
    super();
    this.rsmq = new RedisSMQ(config);
    this.queue = {};

    this.MSG_QUIT = 'MSG_QUIT';
    this.NORMAL = 'NORMAL';

    this.workingType = this.NORMAL;


    let self = this;
    this.on('msg', function(msg) {
      console.log('iddddd', msg);
      console.log(self.workingType);
      if (self.workingType !== self.MSG_QUIT) {
        self.workingType = self.MSG_QUIT;
        self.emit('msg-quit', { qname: 'msg' });
      };
    });

    this.on('msg-quit', function(obj) {
      self.getQueueAttributes(obj.qname).then(queue => {
        console.log('queue===========', queue);
        if (queue.msgs > 0) {
          self.receiveMessage({ qname: obj.qname }).then(msg => {
            console.log('received=========', msg);
            self.deleteMessage({ qname: obj.qname, id: msg.id }).then(r => {
              console.log('deleted===========', r);
              self.emit('msg-quit', obj);
            }).catch(e => self.emit('error', e));
          }).catch(e => self.emit('error', e));
        } else {
          self.workingType = self.NORMAL;
        }
      }).catch(e => self.emit('error', e));
    });
  }

  /**
   * create a message queue
   * @param {Object} opts
   * @param {String} opts.qname   The Queue name
   * @param {Number} opts.delay   The time in seconds that the delivery of all new messages in the queue will be delayed
   * @param {Number} opts.vt      The length of time, in seconds, that a message received from a queue will be invisible to other receiving components when they ask to receive messages
   * @param {Number} opts.maxsize The maximum message size in bytes
   */
  createQueue(opts) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.listQueues().then(function(list) {
        if (Array.prototype.includes.call(list, opts.qname))
          return resolve('queue has been created before yet');

        self.rsmq.createQueue(opts, function(err, resp) {
          if (err) return reject(err);
          if (resp == 1) return resolve('queue created');
          reject(resp);
        });
      });
    });
  }

  /**
   * Change the visibility timer of a single message
   * @param {Object} opts
   * @param {String} opts.qname   The Queue name
   * @param {String} opts.id      The message id
   * @param {Number} opts.vt      The length of time, in seconds, that this message will not be visible
   */
  changeMessageVisibility() {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.changeMessageVisibility(opts, function(err, resp) {
        if (err) return reject(err);
        if (resp == 1) return resolve('changeMessageVisibility successful');
        reject('the message was not found');
      });
    });
  }

  /**
   * delete a queue message
   * @param {Object} opts
   * @param {String} opts.qname   The Queue name.
   * @param {String} opts.id      message id to delete
   */
  deleteMessage(opts) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.deleteMessage(opts, function(err, resp) {
        if (err) return reject(err);
        if (resp == 1) return resolve('deleteMessage successful');
        reject('the message was not found');
      });
    });
  }

  handleMessage(opts) {
    return new Promise((resolve, reject) => {

    })
  }

  /**
   * delete a message queue
   * @param {String} qname    The Queue name
   */
  deleteQueue(qname) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.deleteQueue({ qname }, function(err, resp) {
        if (err) return reject(err);
        if (resp == 1) return resolve('deleteQueue successful');
        reject(resp);
      });
    });
  }

  /**
   * Get queue attributes, counter and stats
   * @param {String} qname    The Queue name
   */
  getQueueAttributes(qname) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.getQueueAttributes({ qname }, function(err, resp) {
        if (err) return reject(err);
        /**
         * {Object} resp
         * vt: The visibility timeout for the queue in seconds
         * delay: The delay for new messages in seconds
         * maxsize: The maximum size of a message in bytes
         * totalrecv: Total number of messages received from the queue
         * totalsent: Total number of messages sent to the queue
         * created: Timestamp (epoch in seconds) when the queue was created
         * modified: Timestamp (epoch in seconds) when the queue was last modified with setQueueAttributes
         * msgs: Current number of messages in the queue
         * hiddenmsgs: Current number of hidden / not visible messages. A message can be hidden while "in flight" due to a vt parameter or when sent with a delay
         */
        resolve(resp);
      });
    });
  }

  /**
   * List all queues
   */
  listQueues() {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.listQueues(function(err, list) {
        if (err) return reject(err);
        resolve(list);
      });
    });
  }

  /**
   * Receive the next message from the queue and delete it
   * This method deletes the message it receives right away. There is no way to receive the message again if something goes wrong while working on the message.
   * @param {String} qname    The Queue name
   */
  popMessage(qname) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.popMessage({ qname }, function(err, resp) {
        if (err) return reject(err);

        if (_.isEmpty(resp)) return reject('empty object if no message is there');

        /**
         * {Object} resp
         * message: The message's contents.
         * id: The internal message id.
         * sent: Timestamp of when this message was sent / created.
         * fr: Timestamp of when this message was first received.
         * rc: Number of times this message was received.
         */
        resolve(resp);
      });
    });
  }

  /**
   * Receive the next message from the queue
   * @param {Object} opts
   * @param {String} opts.qname   The Queue name
   * @param {Number} opts.vt      The length of time, in seconds, that the received message will be invisible to others
   */
  receiveMessage(opts) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.receiveMessage(opts, function(err, resp) {
        if (err) return reject(err);

        if (_.isEmpty(resp)) return reject('empty object if no message is there');
        /**
         * {Object} resp
         * message: The message's contents.
         * id: The internal message id.
         * sent: Timestamp of when this message was sent / created.
         * fr: Timestamp of when this message was first received.
         * rc: Number of times this message was received.
         */
        resolve(resp);
      });
    });
  }

  /**
   * Sends a new message
   * @param {Object} opts
   * @param {String} opts.qname
   * @param {String} opts.message
   * @param {Number} opts.delay     The time in seconds that the delivery of the message will be delayed
   */
  sendMessage(opts) {
    let self = this;

    return new Promise((resolve, reject) => {
      self.rsmq.sendMessage(opts, function(err, id) {
        if (err) return reject(err);

        resolve(id);
        self.emit('msg', id);
      });
    });
  }

  /**
   * Sets queue parameters
   * @param {Object} opts
   * At least one attribute (vt, delay, maxsize) must be supplied. Only attributes that are supplied will be modified
   * @param {String} opts.qname   The Queue name
   * @param {Number} opts.vt      The length of time, in seconds, that a message received from a queue will be invisible to other receiving components when they ask to receive messages
   * @param {Number} opts.delay   The time in seconds that the delivery of all new messages in the queue will be delayed
   * @param {Number} opts.maxsize The maximum message size in bytes
   */
  setQueueAttributes(opts) {
    let self = this;
    return new Promise((resolve, reject) => {
      self.rsmq.setQueueAttributes(opts, function(err, resp) {
        if (err) return reject(err);

        /**
         * {Object} resp
         * vt: The visibility timeout for the queue in seconds
         * delay: The delay for new messages in seconds
         * maxsize: The maximum size of a message in bytes
         * totalrecv: Total number of messages received from the queue
         * totalsent: Total number of messages sent to the queue
         * created: Timestamp (epoch in seconds) when the queue was created
         * modified: Timestamp (epoch in seconds) when the queue was last modified with setQueueAttributes
         * msgs: Current number of messages in the queue
         * hiddenmsgs: Current number of hidden / not visible messages. A message can be hidden while "in flight" due to a vt parameter or when sent with a delay
         */
        resolve(resp);
      });
    });
  }

  /**
   * Disconnect the redis client. This is only useful if you are using rsmq within a script and want node to be able to exit.
   */
  quit() {
    return this.rsmq.quit();
  }
}
